package cn.com.pc.content.config;

import cn.com.pc.aaa.AaaClient;
import cn.com.pc.aaa.AaaInterceptor;
import cn.com.pc.aaa.MockAaaInterceptor;
import cn.com.pc.aaa.MockRbacService;
import cn.com.pc.aaa.model.Identity;
import cn.com.pc.content.converter.DateConverter;
import cn.com.pc.content.converter.LocalDateTimeConverter;
import cn.com.pc.content.converter.MapConverter;
import cn.com.pc.content.interceptor.HandleHeaderInterceptor;
import cn.com.pc.content.service.SiteOperatorService;
import cn.com.pc.rbac.client.Permissions;
import cn.com.pc.rbac.client.RbacInterceptor;
import cn.com.pc.rbac.client.RbacService;
import cn.com.pc.rbac.client.Roles;
import cn.com.pc.rbac.client.model.Permission;
import cn.com.pc.rbac.client.model.Role;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.format.FormatterRegistry;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.List;

import static cn.com.pc.aaa.Constants.AAA_IDENTITY;
import static cn.com.pc.aaa.Constants.AAA_IDENTITY_ID;


@Slf4j
@Component
@EnableWebMvc
@RequiredArgsConstructor
public class MvcConfig implements WebMvcConfigurer {

    private final AaaClient aaaClient;
    private final SiteOperatorService siteOperatorService;

    /**
     * 使用是否注册进服务发现来表示运行模式
     * serviceMode = true  表示完整的服务模式，配套网关、服务发现、IDP、RBAC 全套的集成、测试、或者生产模式
     * serviceMode = false 表示开发自己本机调试模式，采用自己模拟的身份和角色调试应用
     */
    @Value("${eureka.client.register-with-eureka:true}")
    boolean serviceMode;

    @Value("${aaa.dev.roles-of-operator:}")
    private String[] rolesOfOperators;

    @Value("${aaa.dev.permissions-of-role:}")
    private String[] permissionsOfRoles;

    private List<String> handleHeaderInterceptorWhiteList = Arrays.asList("/error", "/health", "/extra/**", "/censor-platform/**");

    private List<String> aaaInterceptorWhiteList = Arrays.asList("/error", "/health", "/extra/**", "/censor-platform/**", "/content/**");


    public void addInterceptors(@NotNull InterceptorRegistry registry) {
        // 添加拦截器，配置拦截地址
        registry.addInterceptor(new HandleHeaderInterceptor()).addPathPatterns("/**").excludePathPatterns(handleHeaderInterceptorWhiteList);

//        if (serviceMode) {
//            // 集成完整生产或测试环境 pc-idp + pc-gateway + pc-rbac + consul
//            log.info("+++ Aaa|RbacInterceptor added with aaaClient: " + aaaClient);
//            registry.addInterceptor(new AaaInterceptor(aaaClient)).addPathPatterns("/**").excludePathPatterns(aaaInterceptorWhiteList); // 认证处理
//            registry.addInterceptor(new SiteRbacInterceptor(aaaClient.getRbacService(), siteOperatorService)).addPathPatterns("/**").excludePathPatterns(aaaInterceptorWhiteList); // 授权处理
//
//        } else {
//            // 开发 + 单元测试
//            log.warn("+++ Run in dev and unittest mode!");
//            registry.addInterceptor(new MockAaaInterceptor(aaaClient)).addPathPatterns("/**").excludePathPatterns(aaaInterceptorWhiteList);
//            registry.addInterceptor(new SiteRbacInterceptor(
//                    new MockRbacService(rolesOfOperators, permissionsOfRoles), siteOperatorService)).addPathPatterns("/**").excludePathPatterns(aaaInterceptorWhiteList);
//        }

        // 写死一个角色
        log.warn("+++ Run in standalone mode, only for develop debug!");
        // 认证处理
        registry.addInterceptor(new HandlerInterceptor() {
            @Override
            public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) {
                Identity identity= new Identity();
                identity.setId(0L);
                identity.setName("SYS-debug");
                request.setAttribute(AAA_IDENTITY, identity);
                request.setAttribute(AAA_IDENTITY_ID, identity.getId());
                return true;
            }
        }).addPathPatterns("/**").excludePathPatterns(aaaInterceptorWhiteList);

        // 授权处理
        registry.addInterceptor(new RbacInterceptor(new RbacService() {
            @Override
            public List<Role> listRolesOf(Long aLong) {
                return Roles.build("producer", "other");
            }

            @Override
            public List<Permission> listPermissionsOfOperator(Long aLong) {
                return Permissions.builder()
                        .permission("article", "create", "delete", "read", "edit")
                        .permission("channel", "publish")
                        .build();
            }
        })).addPathPatterns("/**").excludePathPatterns(aaaInterceptorWhiteList);
    }

    /**
     * 允许跨域
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                // 设置允许跨域请求的域名
                .allowedOriginPatterns("*")
                // 是否允许证书（cookies）
                .allowCredentials(true)
                // 设置允许的方法
                .allowedMethods("*")
                // 跨域允许时间
                .maxAge(3600);
    }

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new LocalDateTimeConverter());
        registry.addConverter(new DateConverter());
        registry.addConverter(new MapConverter());
    }
}

